package com.example.rentalclearing.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.example.rentalclearing.common.ClearingResult;
import com.example.rentalclearing.common.ThreadLocalClearingResult;
import com.example.rentalclearing.config.ClearingConfig;
import com.example.rentalclearing.entity.RentalPaymentSchedule;
import com.example.rentalclearing.service.BankRecordHandleService;
import com.example.rentalclearing.service.ClearingService;
import com.example.rentalclearing.service.IRentalPaymentScheduleService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;

@Slf4j
@Service
@RequiredArgsConstructor
public class ClearingServiceImpl implements ClearingService {

    private final IRentalPaymentScheduleService rentalPaymentScheduleService;
    private final BankRecordHandleService bankRecordHandleService;
    private final Executor clearingExecutor;
    private final ClearingConfig clearingConfig;

    @Override
    public ClearingResult startClearing(String clearingDateStr) {
        LocalDate date = LocalDate.parse(clearingDateStr);
        log.info("开始核销任务，日期：{}", date);

        long start = System.currentTimeMillis();
        
        // 使用原子引用保证线程安全
        AtomicInteger totalRecords = new AtomicInteger(0);
        AtomicReference<BigDecimal> totalPrincipal = new AtomicReference<>(BigDecimal.ZERO);
        AtomicReference<BigDecimal> totalInterest = new AtomicReference<>(BigDecimal.ZERO);

        int pageNum = 1;
        // 从配置中获取分页大小
        int pageSize = clearingConfig.getPageSize();
        List<RentalPaymentSchedule> schedules;

        // 使用线程池并发处理多个批次
        List<CompletableFuture<Void>> futures = new ArrayList<>();
        
        // 统计处理的批次数
        AtomicInteger batchCount = new AtomicInteger(0);

        do {
            // 分页查询租金计划表中应收日期小于当前日期且未全部核销的记录，按应收日期升序排序
            schedules = rentalPaymentScheduleService.selectUnwrittenByDateBefore(date, pageNum, pageSize);

            if (CollUtil.isNotEmpty(schedules)) {
                // 增加批次数统计
                batchCount.incrementAndGet();
                
                // 创建局部final变量解决lambda表达式问题
                final List<RentalPaymentSchedule> finalSchedules = new ArrayList<>(schedules);
                // 提交批次处理任务到线程池
                CompletableFuture<Void> future = CompletableFuture.runAsync(() -> processSchedulesBatch(
                        finalSchedules, totalRecords, totalPrincipal, totalInterest), clearingExecutor);
                futures.add(future);
            }

            pageNum++;
        } while (CollUtil.isNotEmpty(schedules) && schedules.size() == pageSize);

        // 等待所有任务完成
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();

        long end = System.currentTimeMillis();
        long duration = (end - start) / 1000;
        
        ClearingResult result = new ClearingResult(
                totalRecords.get(), 
                totalPrincipal.get(), 
                totalInterest.get(), 
                duration);

        log.info("核销完成，耗时：{}秒，批次数：{}，核销总笔数：{}，核销总本金：{}，核销总利息：{}", 
                duration, batchCount.get(), totalRecords.get(), totalPrincipal.get(), totalInterest.get());
        return result;
    }

    /**
     * 处理单个批次的数据
     * @param schedules 租金计划列表
     * @param totalRecords 总记录数（线程安全）
     * @param totalPrincipal 总本金（线程安全）
     * @param totalInterest 总利息（线程安全）
     */
    protected void processSchedulesBatch(List<RentalPaymentSchedule> schedules, 
                                         AtomicInteger totalRecords, 
                                         AtomicReference<BigDecimal> totalPrincipal, 
                                         AtomicReference<BigDecimal> totalInterest) {
        long batchStart = System.currentTimeMillis();
        int processedCount = 0;
        
        for (RentalPaymentSchedule schedule : schedules) {
            try {
                // 为每个租金计划创建独立事务，提高并发性和减少锁竞争
                ThreadLocalClearingResult scheduleResult = bankRecordHandleService.processSingleSchedule(schedule);
                
                // 线程安全地合并结果
                totalRecords.addAndGet(scheduleResult.getTotalRecords());
                totalPrincipal.accumulateAndGet(scheduleResult.getTotalPrincipal(), BigDecimal::add);
                totalInterest.accumulateAndGet(scheduleResult.getTotalInterest(), BigDecimal::add);
                
                processedCount++;
            } catch (Exception e) {
                log.error("处理租金计划时发生异常，计划ID：{}", schedule.getId(), e);
            }
        }
        
        long batchEnd = System.currentTimeMillis();
        long batchDuration = batchEnd - batchStart;
        log.debug("批次处理完成，处理记录数：{}，耗时：{}ms，平均单条记录处理时间：{}ms", 
                processedCount, batchDuration, processedCount > 0 ? batchDuration / processedCount : 0);
    }

}